from django import template
from django import forms
from django.http import HttpResponseRedirect
import datetime
from django.contrib.contenttypes.models import ContentType
from tagging.models import Tag, TaggedItem
from django.db.models import get_model

from pirate_core.helpers import clean_html

from pirate_social.models import RelationshipEvent
from pirate_signals.models import relationship_event
from pirate_social.models import register_relationship_event
from pirate_core import HttpRedirectException, namespace_get, FormMixin, template_for_model

from customtags.decorators import block_decorator
register = template.Library()
block = block_decorator(register)

get_namespace = namespace_get('pp_tag')

"""This templatetags library exposes the functionality fo django-tagging in a 
        pirate-politics templatetags pattern"""
        
def get_link_tag_list(obj,add_tags_in_object=True):
    """Transforms a list of tags into htmls links to add_tag, used in ajax. 
    This link_list is for tag_details, the other list is to add tags Used in combination
    these functions let tag recommendations and insertions occur over ajax/json."""
    opts = obj._meta
        
    al = opts.app_label
    mod = opts.module_name
    
    model = get_model(al, mod)
    filters = {'pk':obj.pk}
    tags = Tag.objects.cloud_for_model(obj,filters=filters)
    
    c_type = ContentType.objects.get_for_model(model)
    
    taglist = []

    for t in tags:
            rels = RelationshipEvent.objects.all() #breaking modularity saves some DB space here, RelationShip event stores the info we need
            rels = rels.filter(ini_object_pk=t.pk,tar_object_pk=obj.pk)
            count = rels.count()
            link = '<a href="/tag_detail.html?_t=' + str(c_type.id) + '&_o=' + str(t.id) + '">' + str(t.name)  + " (" + str(count) + ")" +"</a>"
            taglist.append(link)
    return taglist
        

def get_tag_list(obj,add_tags_in_object=True):
    """Transforms a list of tags into htmls links to add_tag, used in ajax. 
    Grabs tag list or a object's model, ignoring tags from that model to offer
    for recommendation."""
    opts = obj._meta
        
    al = opts.app_label
    mod = opts.module_name
    
    model = get_model(al, mod)

    content_type = ContentType.objects.get_for_model(obj)
    tags = Tag.objects.cloud_for_model(model)
    
    if not add_tags_in_object:
        tags_remove = Tag.objects.get_for_object(obj)
    else:
        tags_remove = []
    taglist = "Recommended Tags: "
    
    itr = 0
    last = False
    for t in tags:
        itr += 1 
        if itr == len(tags): last = True
        if t not in tags_remove:
            try:
                count = t.count
                font_size = t.font_size
                link = "<font size=" + str(font_size) + " ><a href='javascript:;' onClick=" + '"' + "add_tag('" + str(t.name) + "','" + str(obj.id) + "','" + str(mod) + "', '" + str(al) + "');" + '"' + ">"+ str(t.name) + "</a></font>"
                if last != True: link += ", "
            except: link = "(err: " + str(t.name) + ")"
            taglist += link
        if itr >= 15: break #hard limit to tag recommendation, probably should make this dynamic when intelligent tag recommendations are developed
    return taglist
    

@block 
def pp_tag_recommendations(context, nodelist, *args, **kwargs):
    '''
    This block tag can create or process forms to get tags.
    Usage is as follows:

    '''
    context.push()
    namespace = get_namespace(context)

    obj = kwargs.get('object',None)
    
    taglist = get_tag_list(obj)
    
    namespace['taglist'] = taglist

    output = nodelist.render(context)
    context.pop()
    return output  

@block
def pp_get_tags_for_model(context, nodelist, *args, **kwargs):
    '''
    This block tag can create or process forms to get tags.
    Usage is as follows:
        

    '''
    
    context.push()
    namespace = get_namespace(context)

    obj = kwargs.get('object',None)
    
    filters = {'pk':obj.pk}
    try: tags = Tag.objects.cloud_for_model(obj,filters=filters)
    except: tags = []

    namespace['tags'] = tags

    output = nodelist.render(context)
    context.pop()
    return output  

@block
def pp_has_tags(context, nodelist, *args, **kwargs):
    '''
    Returns True if "object" has a Tag model associated with it.   
    '''
    
    context.push()
    namespace = get_namespace(context)

    obj = kwargs.get('object',None)
    
    l = Tag.objects.get_for_object(obj)
    count = l.count()
    if count > 0: ret = True
    else: ret = False
    
    namespace['has_tags'] = ret

    output = nodelist.render(context)
    context.pop()
    return output  
    

@block
def pp_get_tags_for_object(context, nodelist, *args, **kwargs):
    '''
    This block tag can create or process forms to get tags.
    Usage is as follows:
        

    '''
    
    context.push()
    namespace = get_namespace(context)

    obj = kwargs.get('object',None)
    
    filters = {'pk':obj.pk}
    try: tags = Tag.objects.cloud_for_model(obj,filters=filters)
    except: tags = []

    namespace['tags'] = tags

    output = nodelist.render(context)
    context.pop()
    return output  


@block
def pp_get_link_tags_for_object(context, nodelist, *args, **kwargs):
    '''
    This block tag can create or process forms to get tags.
    Usage is as follows:

    '''
    
    context.push()
    namespace = get_namespace(context)
    obj = kwargs.get('object',None)

    try: tags = get_link_tag_list(obj)
    except: tags = ""

    namespace['tags'] = tags
    #namespace['tags'].extend(tags1)
    #namespace['tags'].extend(tags2)
    output = nodelist.render(context)
    context.pop()
    return output  
  
@block
def pp_get_objects_for_tag(context, nodelist, *args, **kwargs):
    '''
    This block tag can create or process forms to get tags.
    Usage is as follows:

    '''
    
    context.push()
    namespace = get_namespace(context)

    tag = kwargs.get('object',None)

    issues = TaggedItem.objects.get_union_by_model(Issue,tag)
    solutions = TaggedItem.objects.get_union_by_model(Solution,tag)
    arguments = TaggedItem.objects.get_union_by_model(Argument,tag)

    namespace['issues'] = issues 
    namespace['solutions'] = solutions 
    namespace['arguments'] = arguments
    
    output = nodelist.render(context)
    context.pop()
    return output    



@block
def pp_tag_form(context, nodelist, *args, **kwargs):
    '''
    This block tag can create or process forms either to create or to modify arguments.
    Usage is as follows:

    {% pp_tag_form POST=request.POST path=request.path object=pp-issue.issue %}
       Do stuff with {{ pp_tag.form }}.
    {% endpp_tag_form %}
    '''
    
    context.push()
    namespace = get_namespace(context)

    obj = kwargs.get('object',None)
    POST = kwargs.get('POST',None)
    tag = kwargs.get('tag',None)
    user = kwargs.get('user',None)  
    path = kwargs.get('path',None)  
    
    if POST and POST.get("form_id") == "pp_tag_form":
        if tag != None:
            Tag.objects.add_tag(obj, tag.name)
        else:
            form = TagForm(POST)       
            #new_arg = form.save(commit=False)
            if form.is_valid():
                tag_list = form.cleaned_data['tag'].split(',')
                for t in tag_list:
                    if len(t) > 0: 
                        clean_tag = clean_html(t.replace(' ','_'))
                        Tag.objects.add_tag(obj, clean_tag)
                        tag = TaggedItem.objects.get(tag_name=clean_tag,object_id=obj.pk)
                        new_tag = tag.tag
                        try:relationship_event.send(sender=new_tag,obj=new_tag,parent=obj,initiator=user)
                        except: namespace['errors'] = "You've already used that tag for this object"
        #raise HttpRedirectException(HttpResponseRedirect(path))
    else:
        form = TagForm()

    namespace['form'] = form
    output = nodelist.render(context)
    context.pop()
    return output    

    
class TagForm(forms.Form):

    form_id = forms.CharField(widget=forms.HiddenInput(), initial="pp_tag_form")
    tag = forms.CharField(widget=forms.TextInput(), initial="")

